Code Snippets

Code Snippets

Morgan-Wall T (2025). rayshader: Create Maps and Visualize Data in 2D and 3D. R package version 0.38.10, https://github.com/tylermorganwall/rayshader, https://www.rayshader.com.

Roussel J, Auty D, Coops NC, Tompalski P, Goodbody TR, Meador AS, Bourdon J, de Boissieu F, Achim A (2020). “lidR: An R package for analysis of Airborne Laser Scanning (ALS) data.” Remote Sensing of Environment, 251, 112061. ISSN 0034-4257, doi:10.1016/j.rse.2020.112061, https://www.sciencedirect.com/science/article/pii/S0034425720304314.

Roussel J, Auty D (2024). Airborne LiDAR Data Manipulation and Visualization for Forestry Applications. R package version 4.1.2, https://cran.r-project.org/package=lidR.

Shade simulation function in R

#library(suncalc)
#library(rayshader)
#library(terra)

#### Setup time intervals and sun positions

#start <-  as.POSIXct("2024-07-17 01:00:00", tz = "America/Los_Angeles")
#end <-  as.POSIXct("2024-07-18 00:00:00", tz = "America/Los_Angeles")

#times <- data.frame(dates = seq(start, end, "hour"))

#sun_pos <- getSunlightPosition(date = times$dates, lat = 49.2827, lon = -123.1207)

shade_sim <- function(pc, sun_calc,name){   #take a LiDAR point cloud,
  alt <- sun_calc$altitude*(180/pi)         #a table of sun positions,
  azim <- sun_calc$azimuth*(180/pi)         #and output file name as inputs
  
  if(alt >= 0){
    dsm <- rasterize_canopy(pc, dsmtin(), res = 2) %>%    #create and shade a dsm
      raster_to_matrix() %>% 
      ray_shade(sunaltitude = alt, sunangle = azim) %>% 
      rast()
  
    writeRaster(dsm, name, overwrite = TRUE)   #write out the result
  }
}

Isolate center tree from a LiDAR point cloud

#Load in 764 segmented point clouds
path <- (list.files("Outputs/Species Level/las_clipped", full.names = TRUE))

rois <- list()
for(i in 1:length(path)){
  rois[[i]] <- readLAS(path[i])
}

#Point clouds are circular regions clipped from larger file. This allowed for the center coordinates to be included in the filename and used in isolating the central tree below
roi_indiv <- list()
for(i in 1:764){
#generate metrics as a table of treeIDs and coordinates
metrics <- crown_metrics(rois[[i]], ~list(z_max = max(Z), z_mean = mean(Z)))

#use filename to create point geometries in the center of the plot
test_centroid <- str_extract(path[i], 
                 "[:digit:]{6}\\.[:digit:]{1}\\_[:digit:]{7}|[:digit:]{6}\\_[:digit:]{7}") %>%
  str_replace("_", ", ") %>%
  str_split("\\,\\s",2) %>%
  unlist() %>%
  as.numeric() %>%
  st_point() %>%
  st_geometry()

st_crs(test_centroid) <- 26910
  
#add new row to metrics table that contains distance from tree to center
new_metrics <- mutate(metrics, dist = st_distance(metrics, test_centroid))
  
#central tree is the tree with the shortest distance to the centroid
center_tree <- filter(new_metrics, dist == min(dist))
  
#assign it back out to a list
roi_indiv[[i]] <- filter_poi(rois[[i]], treeID == center_tree$treeID)
}